perm filename VDSK.FAI[CMS,LCS] blob
sn#430687 filedate 1979-04-05 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00029 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 Floppy disk file system.
C00006 00003 OCTL: 0 Lsbyte of octal to decimal.
C00008 00004 ID0: 113 Write two sectors.
C00009 00005 Add restore to retry?
C00011 00006 IDLSET: LDAI 0
C00012 00007 DCODE: LDXI NCMDS # of commands.
C00014 00008 Write command to FDSKC. No wait or * NTRYS.
C00016 00009 IRQ maskable interrupt routine.
C00018 00010 Non-maskable DRQ interrupt.
C00019 00011 Directory look up.
C00021 00012 Read 1st sec of a directory. Returns with 0 or Ebits.
C00023 00013 Open read file.
C00025 00014 Read a block of the file.
C00027 00015 Create file routine
C00029 00016 Write file.
C00031 00017 SWBUF: JSR SWDBUF Swap disk buffers.
C00032 00018 CLOZE: JSR GEOT Wait for EOT.
C00034 00019 Update directory header.
C00036 00020 PSF: JSR GEOT
C00038 00021 Delete file.
C00040 00022 DIR: JSR GEOT Wait for EOT.
C00043 00023 Compress holes.
C00045 00024 File found. Save file address.
C00047 00025 FIXDIR: CLV V ← 0.
C00050 00026 FORM: JSR GEOT
C00052 00027 Decimal output routine.
C00054 00028 MOTOFF: LDAI MOFF Turn motor off.
C00056 00029 GDIG: STAZ DIGIT
C00057 ENDMK
C⊗;
;Floppy disk file system.
.INSERT ASMBL.FAI[CMS,LCS]
ZERO ← 0
LOC ZERO ;Fail offset
CBLK: 0 ;Ram command block.
CCNT: 0 ;C parameter count.
CLEN: 0 ;C # of sectors.
CSEC: 0 ;C sector
CTRK: 0 ;C track
0
FOTRK: 0 ;Format track number.
0
FCMD: 0 ;Disk command pointer.
FCMDH: 0
CMDJMP: 0 ;Indirect command jump.
CJMPH: 0 ;Msbyte.
BUSY: 0 ;Busy flag.
ERFLG: 0 ;Error flag/code.
SVERR: 0 ;Saved error.
CEFLG: 0 ;Communication error flag.
RFOPEN: 0 ;Read file open flag.
WFOPEN: 0 ;Write file open flag
DIRC: 0 ;Data direction
FLEN: 0 ;File length. In sectors.
FITRK: 0 ;Compress file track.
FISEC: 0 ;Compress file sector.
SREM: 0 ;Sectors remaining.
NTRYS: 0 ;Number of retrys before error.
MO: 0 ;Motor on flag. MFLG = TL or TH?
INDEX: 0 ;State of index pin.
TL: 0 ;Motor time out low.
TH: 0 ;Time out high.
DIRCNT: 0 ;Directory sector count.
HLEN: 0 ;Hole sector count.
HTRK: 0 ;Hole track number.
HSEC: 0 ;Hole sector number.
SVHY: 0 ;Hole directory index. HDI.
SVHSEC: 0 ;Hole directory sector. HDS.
SVSEC: 0 ;Other directory sector. FDS.
SVOSEC: 0 ;Old directory sector.
FDI: 0 ;File directory index.
FBLK: 0 ;File block
FNAME: BLOCK 11 ;9 Chr file name.
NSEC: 0 ;Number of sectors in file.
FTRK: 0 ;Disk track number
FSEC: 0 ;Disk sector number
BLOCK 3 ;For FBLK = 20.
DBLK: 0 ;Directory block
DSEC: 0 ;Number of sectors in directory.
FFDIR: 0 ;First free directory block. FDI?
FFTRK: 0 ;First free data track
FFSEC: 0 ;First free data sector
FBLKS: 0 ;Number of free sectors. In sectors.
FBH: 0 ;Msbyte
0
CKSUM: 0 ;Check sum.
SPOINT: 0 ;SI/O pointer.
SPOH: 0 ;Msbyte
DPOINT: 0 ;Disk buffer bointer.
DPOH: 0 ;Msbyte
OCTL: 0 ;Lsbyte of octal to decimal.
OCTH: 0 ;Msbyte.
DIGIT: 0 ;Tens or hundreds.
LOC ZERO+1000
FBUF: 0 ;Disk data buffer.
LOC FBUF+400
FBUF1: 0 ;Other buffer.
;PROM Start address.
LOC ZERO+174000
FCTBL:
DINIT ← 0
65 ;Specify
4 ;Parameter count.
352 ;H unload I cnt./ H load time.
=25 ;Head settling time in ms*2.
=20 ;Step rate in ms*2.
15 ;Init
SBT ← 6
65 ;Specify
4
0 ;Current track.
377
377 ;No bad tracks.
20 ;Surface zero bad tracks command.
DMA ← 14
172 ;Write special register.
2
0 ;DMA and double actuator.
27 ;Mode register.
RESTOR ← 20
151 ;Seek track zero command.
1 ;With head load.
0 ;Track zero
MON ← 23
172 ;Write special register.
2 ;Clear out pins.
40 ;Motor on bit.
43 ;Drive control output register.
MOFF ← 27
172 ;Write special register.
2
0 ;Motor off.
43 ;Drive control output register.
RDSTAT ← 33
154 ;Read drive status command.
0
RH0: 123 ;Read two sectors command.
3
2 ;# of sectors.
1 ;Header sector number
0 ;Header track number
WH0: 113 ;Write two sectors command.
3
2 ;# of sectors.
1 ;Header sector number.
0 ;Header track number.
ID0: 113 ;Write two sectors.
3
=16 ;# of sectors.
1 ;First sector.
0 ;Track zero.
FORMT: 143 ;Format track command.
5
=16 ;Gap 1 -6.
0 ;Gap 5. No index mark.
=16 ;Sectors per track.
=27 ;Gap 3 -6.
0 ;Format track number.
RETRY ← =10 ;Number of retrys until error.
DMARK ← 74 ;Directory mark
FMARK ← 72 ;File mark
HMARK ← 67 ;Hole mark.
;Add restore to retry?
;Add write protect and not ready error codes.
;Put MOTOFF in GCHR?
;Power on reset.
RST: LDXI 377 ;Setup stack.
TXS
CLD ;Clear decimal mode.
;Reset I/O
SIOC ← 20000 ;SI/O command register.
SIOD ← 20001 ;SI/O data register.
FDSKC ← 10000 ;Disk command/status register
FDSKP ← 10001 ;Disk parameter/result register
FDSKR ← 10002 ;Disk reset register.
FDRQ ← 14000 ;Disk DMA data request
;Init floppy disk controller.
LDAI 1 ;RESET DISK AGAIN.
STA FDSKR
NOP
NOP
NOP
LSRA ;A ← 0.
STA FDSKR
;A = DINIT.
JSR PCMD ;Prom command.
LDAI DMA ;Setup DMA mode.
TAX ;X ← 14. For POW.
JSR PCMD
JSR POW ;POWER ON DELAY.
LDAI RESTOR ;Restore track zero.
JSR PCMD
LDAI SBT ;Setup bad tracks
JSR PCMD
STYZ MO ;Init motor on flag.
;Reset SI/O
LDAI 3 ;Reset bits
STA SIOC
LDAI 25 ;ACIA control word.
STA SIOC
;Init RAM
LDAZ DSEC
STAZ DIRCNT ;Point to end of directory.
IDLSET: LDAI 0
LDXI 6 ;Clear all error flags, etc.
CLRF: STAZX BUSY
DEX
BPL CLRF
CLI ;Enable interrupts.
TWOS ← 5 ;3 = 1.77s, 4 = 2.3s.
IDLE: BITZ MO ;Check if motor on.
BPL GSOH
LDA SIOC ;Read SI/O status.
LSRA ;Get rcvr. full bit.
BCS GSOH
DEX ;Time out countdown.
BNE IDLE
DECZ TL
BNE IDLE
DECZ TH
BNE IDLE
INX
INCZ TL
INCZ TH
BITZ BUSY ;Check if disk is busy.
BMI IDLE
JSR MOTOFF ;Turn off motor.
GSOH: JSR GCHR ;Wait for SOH.
CMPI 1 ;<SOH>.
BNE ILLCMD ;Error.
JSR GCHR ;Wait for command.
DCODE: LDXI NCMDS ;# of commands.
DL: CMPX CMDTBL ;Check if valid command.
BEQ JCMD
DEX
BPL DL
;Illegal command.
ILLCMD: LDXI 4 ;Command error code.
OCLR: JSR OCHR ;Output status.
JMP IDLSET ;Reset flags.
JCMD: LDAX JLTBL ;Get lsbyte of jump address.
STAZ CMDJMP
LDAX JHTBL ;Get msbyte.
STAZ CJMPH
JMPIN CMDJMP ;Excute command.
NCMDS ← =9 ;# of commands -1.
CMDTBL: "P" ;Perform special function.
"K" ;Delete file.
"B" ;Free blocks
"N" ;Next directory block.
"D" ;Open directory.
"C" ;Close write file.
"E" ;Enter write file.
"O" ;Open read file.
"W" ;Write data
"R" ;Read data
JLTBL: PSF∧377 ;Lsbyte of command address.
KIL∧377
BLKS∧377
NXTDIR∧377
DIR∧377
CLOZE∧377
ENTR∧377
OPIN∧377
WRITE∧377
READ∧377
JHTBL: PSF⊗-10 ;Msbyte of command address.
KIL⊗-10
BLKS⊗-10
NXTDIR⊗-10
DIR⊗-10
CLOZE⊗-10
ENTR⊗-10
OPIN⊗-10
WRITE⊗-10
READ⊗-10
;Write command to FDSKC. No wait or * NTRYS.
PCMD: STAZ FCMD ;Prom command with no retrys.
LDAI 370 ;Msbyte of command table addr.
STAZ FCMDH
LDAI 0
STAZ NTRYS
BEQ SETPO ;Jump.
RCMD: LDAI 0 ;Ram command with no retrys.
SETRY: STAZ NTRYS
TRY: LDAI 0
STAZ FCMD
STAZ FCMDH
LDAI 377 ;Set busy.
STAZ BUSY
LDAI 0
SETPO: STAZ DPOINT ;Reset disk DMA pointer.
BSYW: LDA FDSKC ;Wait until not busy.
BMI BSYW
LDYI 0
LDAIY FCMD ;Get command code.
STA FDSKC ;Write in disk control reg.
INCZ FCMD ;Point to parameter count.
LDAIY FCMD ;Get count.
BEQ NOPAR ;If no parameters
TAY
PARW: LDA FDSKC ;Read status
ANDI 40 ;P reg full bit.
BNE PARW ;Wait if still full.
LDAIY FCMD ;Parameter
STA FDSKP
DEY
BNE PARW ;More left?
NOPAR: RTS ;Y = 0
WBUFR: LDAI 113 ;Write two sectors command.
STAZ CBLK
WUF: LDAI 377
STAZ DIRC ;Set to write.
;Disk command with retrys on read error.
RCMDR: LDAI RETRY ;RAM disk command.
BNE SETRY
RCMDW: JSR RCMDR ;Read command wait.
BW: BITZ BUSY
BMI BW ;Wait until done
LDAZ ERFLG ;Get error bits.
RTS ;Return with error bits.
;IRQ maskable interrupt routine.
IRQV: PHA ;Save Registers.
TYA
PHA
;Wait for result bit?
LDA FDSKP ;Read disk result register.
ANDI 36 ;Flush ddbit
STAZ ERFLG
LDYI 200
CKIRQ: INY ;IRQ reset delay.
BNE CKIRQ
TAY ;Test error flags.
BNE DSKERR ;Disk error.
LDAZ CBLK ;Get last disk command.
CMPI 113 ;Check if write command.
BNE NOTBSY
LDAI 137 ;Disk verify command.
STAZ CBLK
BNE ITRY ;Verify write.
DSKERR: ANDI 20 ;Bad bit
BEQ CKTRY
;Dsk error: RDY,WRT fault, etc.
;Fix for WPRT etc.
STAZ SVERR ;Save bad error.
;Read drive status if not ready for clear.
;Check if not ready?
JSR RDRVST ;Read dirve status.
;Error codes before RDRVST.
;20 Not ready.
;21 Write protect.
;22 Restore error.
;23 File not found.
;30 Sector not found.
JMP NOTBSY
CKTRY: LDAZ NTRYS
BEQ SETERR
DECZ NTRYS
ITRY: JSR TRY ;Retry command.
BEQ RTRN ;Jump. Wait until done.
SETERR: LDAI 377 ;Retry error.
STAZ SVERR
NOTBSY: LDAI 0
STAZ BUSY ;Set done
STAZ DIRC ;Reset to read.
BEQ RTRN ;Jump.
;Non-maskable DRQ interrupt.
NMIV: PHA ;Save registers
TYA
PHA
LDYI 0 ;No index.
BITZ DIRC ;Get direction.
BMI WDRQ ;Disk write.
LDA FDRQ ;Read byte from disk.
STAIY DPOINT ;Save it in FBUF
INCPO: INCZ DPOINT
RTRN: PLA ;Restore Registers.
TAY
PLA
RTI ;Return
WDRQ: LDAIY DPOINT ;Get byte from FBUF.
STA FDRQ ;Write into disk data register.
JMP INCPO
;Directory look up.
;Returns with file found, fnf, or read error.(0,200,XX)
LOKUP: LDXI 0
GNAME: JSR GCHR ;Get name.
CMPI 4 ;<EOT>.
BEQ CKNAME
STAZX FNAME
INX
CPXI =10 ;9 Chr file name + EOT.
BCC GNAME
ILCJMP: PLA ;One level pop to ILLCMD.
PLA
JMP ILLCMD
CKNAME: TXA ;Test X.
BEQ ILCJMP ;No file name.
LDAI " " ;<Space>.
PAD: STAZX FNAME ;Pad file name with spaces.
INX
CPXI =9
BCC PAD
LDAZ CEFLG ;Check for communication error.
BNE ILCJMP
JSR RHDR ;Read directory header sector.
BNE LUERR
LDAI FMARK
STAZ FBLK
GETS: JSR RNDS ;Read next 2 directory sectors.
BNE LUERR
;Y = 0
CKDIR: LDXI 0
CKNAM: LDAY FBUF
CMPZX FBLK ;Look for file name.
BNE NXTF ;No match
INY
INX
CPXI =10 ;9 chrs. + FMARK.
BCC CKNAM
;Names match
FMOV: LDAY FBUF ;Save file record.
STAZX FBLK
INY
INX
CPXI 20
BCC FMOV
LDAI 0 ;Return with file found.
LUERR: RTS ;Return with error bits.
NXTF: TYA ;Point to next file record.
ORAI 17
TAY
INY
BNE CKDIR
DECZ SREM ;Check if more sectors.
DECZ SREM
BNE GETS
LDAI 200 ;Return file not found code.
RTS
;Read 1st sec of a directory. Returns with 0 or Ebits.
RHDR: JSR MOTON ;Turn on motor and delay.
LDXI 4
CSET: LDAX RH0 ;Setup command list.
STAZX CBLK
DEX
BPL CSET
JSR SETDPO ;Point disk to FBUF.
JSR RSEC ;Read it * 16.
BNE HERR
LDA FBUF
CMPI DMARK ;Check for directory.
BNE HERR ;Fix for if DMARK≠FBUF=0.
LDXI 7
GHL: LDAX FBUF
STAZX DBLK
DEX
BPL GHL
LDAZ DSEC
STAZ SREM ;Number of sectors in dir.
STAZ DIRCNT ;Reset directory count.
LDAI 0 ;No error return
HERR: RTS ;Return with error bits.
;Read next dir. sector. Returns with error bits.
RNDS: INCZ CSEC ;Read next dir sec.
INCZ CSEC
;Read a block routine.
REED: LDAI 123 ;Read two sectors command.
STAZ CBLK
RSEC: LDAI 0 ;Reset file open flags.
STAZ RFOPEN
STAZ WFOPEN
JSR RCMDW ;Disk command wait * RETRYS
BEQ GOTIT ;Good read
INY ;Y ← 1. Directory 1.
STYZ CTRK
JSR RCMDW ;Y ← 0
STYZ CTRK ;Fix CTRK for next read.
GOTIT: RTS ;Return with error bits.
SETDPO: LDAI FBUF⊗-10 ;Point disk to FBUF.
STAZ DPOH
LDAI 0
STAZ DPOINT
RTS
INCSEC: INX ;Increment sector and track address.
INX
CPXI =16
BCC NXTBLK
ADCI 0 ;TRK ← TRK + 1.
LDXI 1 ;First sector.
NXTBLK: RTS
;Open read file.
OPIN: BITZ WFOPEN ;Check if write file open.
BPL LOOK
JMP FAO ;File already open error.
LOOK: JSR LOKUP ;Lookup file FNAM
BEQ SETOPN
CMPI 200 ;File not found code.
BEQ NACKIT
JMP DIRERR ;Directory read error
NACKIT: JMP FNF ;File not found.
SETOPN: LDAZ FTRK ;Get track and sector
STAZ CTRK
LDAZ FSEC
STAZ CSEC
LDAZ NSEC ;Get file length.
STAZ SREM
;Fill FBUF
JSR RCMDR ;* NTRYS and no wait.
JSR SETSPO ;Point SPOINT to FBUF.
LDAI 377
STAZ RFOPEN
ACK: LDXI 20 ;<ack>
OACK: JSR OCHR ;Output byte.
JMP IDLE ;No flag clear.
SETSPO: LDAI FBUF⊗-10 ;Reset SI/O pointer.
STAZ SPOH
LDAI 0
STAZ SPOINT
RTS
;Read a block of the file.
READ: JSR GEOT ;Wait for EOT.
BITZ RFOPEN ;Check if file open.
BMI CKS
JMP FNF ;File not found
CKS: LDAZ SREM ;Check for end of file.
BNE READO ;For FLEN = 0.
EOF: LDXI 6 ;End of file error code.
JMP OCLR ;Output X and clear flags.
READO: JSR BW ;Wait until not busy.
BEQ NXTBUF
DRERR: LDXI 14 ;Disk read error.
JMP OCLR ;Clear all flags.
NXTBUF: STAZ CKSUM
DECZ SREM ;Check if end of file.
DECZ SREM
BEQ ACKIT
;Start read of next buffer.
JSR NXTSEC ;Increment CSEC and CTRK.
RNS: JSR SWDBUF ;Swap disk buffers.
JSR MOTON ;Turn on motor.
JSR RCMDR ;No wait. Y=0. Set CBLK?
ACKIT: JSR ACKSTX ;Output <ack> and <stx>.
;Y = 0
RDIT: LDAIY SPOINT ;Output a buffer full.
JSR OCHECK ;Output byte and update check sum.
INY
BNE RDIT
JSR SWSBUF ;Swap SI/O buffers.
OUTCK: LDAZ CKSUM ;Output check sum.
EORI 377
TAX
INX
JMP OACK ;Output it and no flag clear.
SWSBUF: LDAZ SPOH
EORI 1 ;Swap SI/O buffers.
STAZ SPOH
RTS
;Create file routine
ENTR: BITZ WFOPEN ;Check if file already open
BPL LOKIT
FAO: LDXI 10 ;File already open error.
BNE OAJMP ;Output it. No flag clear.
LOKIT: JSR LOKUP ;Check if file already exists.
BEQ FEXIST ;Check if file exists
CMPI 200 ;Not in dir. code
BEQ FULCK ;If = then Y = 0.
DIRERR: LDXI 13 ;Directory read error code.
CLRJMP: JMP OCLR ;Clear flags.
FEXIST: LDXI 2 ;File exists error code.
BNE CLRJMP ;Clear flags.
DSKFUL: LDAI =35 ;Disk full.
STAZ FFTRK ;Set full flag.
DFUL: LDXI 5 ;Disk full code.
OAJMP: JMP OACK ;No flag clear?
FULCK: LDAZ FFTRK ;Get first free track.
CMPI =35 ;Check if disk full.
BCS DFUL
STAZ CTRK ;Point to new file.
STAZ FTRK ;Setup file block.
STAZ CLEN ;Track number for seek.
LDAI 151 ;Seek track command.
STAZ CBLK
INY ;Y ← 1.
STYZ CCNT
JSR RCMD ;Seek track. Y = 0
STYZ FLEN ;Reset file length.
DEY ;Set write file open flag.
STYZ WFOPEN
LDXI 3 ;Setup command parameter count.
STXZ CCNT
STXZ DPOH ;Point disk to other buffer.
DEX ;Setup number of sectors.
STXZ CLEN
LDXZ FFSEC
STXZ FSEC ;Setup file block.
DEX ;-2 For inc. before write.
DEX
STXZ CSEC
JSR SETSPO ;Point SI/O to FBUF.
JMP ACK ;Return with no errors
;Write file.
WRITE: JSR GEOT ;Wait for EOT.
BITZ WFOPEN ;Check if file open.
BMI WIT
JMP FNF ;File not found
WIT: LDAZ FFTRK
CMPI =35 ;Check if disk is full.
BCS DSKFUL
JSR PACK ;Output <ACK>.
JSR GCHR ;Wait for STX.
CMPI 2 ;<STX>.
BNE COMERR ;No STX.
LDYI 0 ;Init buffer index.
STYZ CKSUM ;Init check sum.
WLOOP: JSR GCHR ;Fill FBUF.
STAIY SPOINT
CLC
ADCZ CKSUM ;Update check sum.
STAZ CKSUM
INY
BNE WLOOP
JSR GCHR ;Get check sum.
CLC
ADCZ CKSUM ;Check for check sum error.
BNE COMERR
LDAZ CEFLG ;Check for communication error.
BEQ WBUF
COMERR: LDXI 11 ;Communication error.
JMP OCLR ;Reset flags.
WBUF: JSR BW ;Wait until last buffer done.
BEQ NFBLK
JMP DRERR ;Write error. Verify error?
NFBLK: JSR NXTSEC ;Increment CSEC and CTRK.
CMPI =35 ;Check if disk is full.
BCC SWBUF
JMP DSKFUL
SWBUF: JSR SWDBUF ;Swap disk buffers.
JSR MOTON ;Turn on motor.
JSR WBUFR ;Write buffer.
JSR SWSBUF ;Swap SI/O buffers.
INCZ FLEN ;Update file length.
INCZ FLEN
JMP ACK ;No error return.
WBUFW: JSR WBUFR ;Write it.
JMP BW ;Return with E bits when done.
SWDBUF: LDAZ DPOH
EORI 1 ;Swap disk buffers.
STAZ DPOH
RTS
NXTSEC: LDXZ CSEC ;Increment CSEC and CTRK.
LDAZ CTRK
JSR INCSEC
STXZ CSEC
STAZ CTRK
RTS
CLOZE: JSR GEOT ;Wait for EOT.
BITZ WFOPEN ;Check if file open
BMI UPDIR
JMP ACKCLR ;No file open, <ack> anyway.
;Update directory
UPDIR: JSR BW ;Wait until not busy.
BEQ BUMP
JMP DRERR ;Last buffer write error?
BUMP: LDAZ FLEN ;Save file length.
STAZ NSEC
JSR NXTSEC ;Get new FFSEC and FFTRK.
STAZ HTRK
STXZ HSEC
;Read last directory sector.
JSR MOTON ;Turn on motor.
LDXZ DSEC ;Last directory sector -1.
INX ;Bump.
STXZ CSEC
STXZ SVOSEC ;Save last dir. sec. number.
JSR SETDPO ;Point to FBUF. A ← 0
STAZ CTRK ;Track zero.
JSR REED ;Read next dir. sec.
BEQ CLOZIT
CLZERR: JMP DIRERR ;Directory read error.
CLOZIT: LDYZ FFDIR
TAX ;X ← 0
NAMEIT: LDAZX FBLK ;BLT FBLK into directory
STAY FBUF
INY
INX
CPXI 20 ;FBLK Length
BCC NAMEIT
;Update directory header.
WRTH0: TYA ;Get next free directory block.
STAZ FFDIR
BNE UPFF
INCZ DSEC ;Next sector
INCZ DSEC
LDAZ DSEC ;Check if directory full.
CMPI =15
BCC UPFF
LDAI =14 ;Last directory sector.
STAZ DSEC
LDAI =35 ;Set disk full.
STAZ HTRK
UPFF: LDAZ HSEC ;Point to next free block.
STAZ FFSEC
LDAZ HTRK
STAZ FFTRK
SEC
LDAZ FBLKS
SBCZ FLEN ;Update free blocks.
STAZ FBLKS
BCS WDIR
DECZ FBH
WDIR: LDXI 7 ;Header length.
HLOOP: LDAZX DBLK ;BLT Header into directory.
STAX FBUF1 ;Other buffer.
DEX
BPL HLOOP
LDAI 1 ;First sector.
STAZ SVSEC
JSR WBUFS ;Write 4 bufs on 2 tracks.
BNE CLZERR ;Check for close error.
STAZ WFOPEN ;Close write open flag.
ACKCLR: LDXI 20 ;<Ack>.
JMP OCLR ;Output <Ack> and clear flags.
;Add error checks after WBUFWs?
WBUFS: JSR WBUFW ;Write dir. 0.
LDAZ SVSEC ;First sector.
STAZ CSEC
JSR SWDBUF ;Swap disk buffers.
JSR WBUFW ;Write dir. header 0. Y←0
INY ;Y ← 1. Directory 1.
STYZ CTRK
JSR WBUFW ;Write dir. header 1.
;Write last track directory.
LDAZ SVOSEC ;Get last dir.sec. number.
STAZ CSEC
JSR SWDBUF ;Swap buffers.
JSR WBUFW
LDAZ SVERR ;?
RTS ;Return with error bits.
PSF: JSR GEOT
JSR PACK ;<Ack>
JSR GCHR ;Wait for SOH.
CMPI 1 ;SOH
BNE PSFERR
JSR GCHR ;Wait for special function cmd.
CMPI "Q" ;Compress holes.
BNE CKF
JSR GEOT ;Wait for EOT.
JMP CMPRES
CKF: CMPI "F" ;Format disk.
BNE CKI
JMP FORM
CKI: CMPI "I" ;Initialize directory.
BEQ IDIR
PSFERR: JMP ILLCMD ;Command error.
;Initialize directory.
IDIR: JSR GEOT ;Wait for EOT.
JSR MOTON ;Turn on motor.
FORMIN: LDXI 10 ;Entry from format command.
LDAI 0
ZE: STAX FBUF ;Zero directory
INX
BNE ZE
LDXI 7
DIIL: LDAX DIT ;Init dir.
STAX FBUF
DEX
BPL DIIL
LDXI 4
SETC: LDAX ID0 ;Setup CBLK.
STAZX CBLK
DEX
BPL SETC
JSR SETDPO ;Point disk to FBUF.
JSR WS2TRK ;Write sector on two tracks.
BNE IDERR
JMP ACKCLR ;<Ack> and clear flags.
IDERR: LDXI 7 ;Init dir. error.
JMP OCLR ;Reset flags.
WS2TRK: JSR WBUFW ;Write first header and dir.
INY ;Y←1. Directory 1.
STYZ CTRK
JSR WBUFW ;Write last directory.
LDAZ SVERR ;Return with all errors.
RTS
DIT: DMARK
2 ;# of sectors
0 ;FFDB
2 ;FFT
1 ;FFS
=528∧377 ;FBL
=528⊗-10 ;FBH
0
;Delete file.
KIL: JSR LOKUP
BEQ KILIT
;Check for directory read error?
FNF: LDXI 3 ;File not found.
JMP OCLR
KILIT: DEY ;Fix directory pointer.
LDAI HMARK
STAY 761 ;FBUF - 17
LDXZ CSEC
STXZ SVOSEC ;Save directory sector #.
INY ;Next directory block.
CPYZ FFDIR ;Check if last dir. block.
BNE DEL
DEX
TYA ;A ← Old FFDIR.
BNE CKSEC
INX
INX
CKSEC: CPXZ DSEC ;Check if last block in dir.
BNE DEL
SEC ;File = last file in dir.
SBCI 20 ;Point to FFDIR -1 block.
STAZ FFDIR
TAX
LDAI 0
STAX FBUF ;Null record entry.
LDAZ FTRK ;Point first free track to
STAZ FFTRK ;deleted file.
LDAZ FSEC
STAZ FFSEC
CLC
LDAZ FBLKS
ADCZ NSEC ;Add # of sectors in file
STAZ FBLKS ;to free block count.
BCC CKDSEC
INCZ FBH
CKDSEC: TYA ;Test Y.
BNE DEL
DECZ DSEC ;Directory sector -2.
DECZ DSEC
DEL: JMP WDIR ;Write header and directory.
;Output free blocks.
BLKS: JSR GEOT ;Wait for EOT.
JSR RHDR ;Read directory header.
BNE JDER ;Directory read error.
JSR ACKSTX ;Output <ack> and <stx>.
LDAZ FBH ;Get msbyte of free blocks.
LDXZ FBLKS ;Get lsbyte.
JSR ODEC ;Output 3 decimal digits.
OEOT: LDXI 4 ;<EOT>.
JMP OCLR ;Clear flags.
DIR: JSR GEOT ;Wait for EOT.
JSR RHDR ;Read header.
BEQ RQDIR
JDER: JMP DIRERR ;Error.
RQDIR: STAZ DIRCNT ;Point to start. A = 0.
JACK: JMP ACKCLR ;<Ack> and clear flags.
NXTDIR: JSR GEOT ;Wait for EOT.
LDXZ DIRCNT ;Check if at end.
CPXZ DSEC ;Check if done.
BCC NXD
JMP EOF
NXD: INX
INX
STXZ DIRCNT ;Update directory count.
INX ;Bump past dir. header.
STXZ CSEC
JSR MOTON ;Turn on motor.
JSR RSEC ;Read next directory sector.
BNE JDER
JSR ACKSTX ;Output <ACK> and <stx>.
LDAI 160 ;((15+12)*=16)∧377.
STAZ CKSUM ;Init check sum.
;Y = 0
DOL: LDAY FBUF ;Find file in FBUF.
CMPI FMARK
BNE OUTZ
LDXI 11 ;9 Chr file name.
STXZ HSEC
ONAME: LDXY 1001 ;FBUF + 1.
JSR OCHRCK ;Output it.
INY
DECZ HSEC
BNE ONAME
LDXI " " ;Output two spaces.
JSR OCHRCK ;Output and update check sum.
JSR OCHRCK ;Output and update check sum.
LDAI 0 ;Msbyte of file length.
LDXY 1001 ;Get lsbyte from FBUF.
JSR ODEC ;Output 3 ascii decimal digits.
CLOUT: LDXI 15 ;<CR>.
JSR OCHR
LDXI 12 ;<LF>.
JSR OCHR
TYA
ORAI 17 ;Next file block.
TAY
INY
BNE DOL
JMP OUTCK ;Output check sum.
OUTZ: LDAI 16 ;9 chr. file name + 5.
STAZ HSEC
LDXI 0 ;Null file block. (Hole)
ZOUT: JSR OCHR ;Output nulls.
DECZ HSEC
BNE ZOUT
BEQ CLOUT ;Jump.
;Compress holes.
CMPRES: JSR RHDR ;Read directory header.
BNE DJ
SQEZ: JSR RNDS ;Read directory.
BNE DJ
;Y = 0
ENDCK: LDXZ CSEC ;Check if at end of dir.
DEX ;Unbump.
CPXZ DSEC ;Check if same sector.
BCC CKHOL
CPYZ FFDIR ;Check if less that last record.
BCC CKHOL
JMP ACKCLR ;Done.
CKHOL: LDAY FBUF ;Find first hole.
CMPI HMARK ;Look for a hole.
BEQ HOLE
TYA
CLC
ADCI 20 ;Next directory record.
TAY
BNE ENDCK
BEQ SQEZ ;Jump.
DJ: JMP DIRERR ;Directory read error.
;Hole found.
HOLE: LDAY 1013 ;FBUF + TRK#
STAZ HTRK ;Save hole track.
LDAY 1014 ;FBUF + SEC#
STAZ HSEC ;Save hole sector.
STYZ SVHY ;Save hole dir. index.
LDAZ CSEC
STAZ SVHSEC ;Save hole dir. sector.
FINDF: CLC ;Update free blocks.
LDAZ FBLKS
ADCY 1012 ;FBUF + FLEN.
STAZ FBLKS
BCC FNXTF
INCZ FBH
FNXTF: TYA ;Find next file.
CLC
ADCI 20 ;Next dir. record.
TAY
BNE CKEND
JSR RNDS ;Read next directory block.
BNE DJ ;Error.
;Y = 0.
CKEND: LDXZ CSEC
DEX ;Unbump.
CPXZ DSEC ;Check if last dir. sector.
BCC CKFIL
CPYZ FFDIR ;Check if past last record.
BCC CKFIL
JMP DONE
CKFIL: LDAY FBUF ;Look for file mark.
CMPI FMARK
BEQ FFOUND
CMPI HMARK ;Check if a hole.
BNE FNXTF
BEQ FINDF ;Jump and add hole length.
;File found. Save file address.
;FBUF ← File directory.
FFOUND: STYZ FDI ;Save file directory index.
INX ;Save file directory sector #.
STXZ SVSEC ;SVSEC ← FDS.
LDXI 0
JSR FMOV ;Save FBLK. Y ← Y + 20.
JSR SWDBUF ;Swap disk buffers.
LDAZ NSEC ;Get file length.
STAZ FLEN
LDAZ FTRK ;Get file address.
LDXZ FSEC
LDYZ HTRK ;Save next file address.
STYZ FTRK
LDYZ HSEC
STYZ FSEC
;Fill hole.
FILLIT: STAZ FITRK ;Save file track.
STXZ FISEC ;Save file sector.
STAZ CTRK
STXZ CSEC
LDAI 123 ;Read two sectors command.
STAZ CBLK
JSR RCMDW ;Read a block.
BNE DJMP
LDAZ HTRK ;Point to hole.
STAZ CTRK
LDXZ HSEC
STXZ CSEC
JSR INCSEC ;Increment hole address.
STAZ HTRK ;New FFTRK.
STXZ HSEC ;New FFSEC.
JSR WBUFW ;Fill hole.
BNE DJMP
DECZ FLEN ;FLEN ← FLEN - 2.
DECZ FLEN
BEQ CUPD ;Check if hole filled.
LDXZ FISEC
LDAZ FITRK
JSR INCSEC ;Next file sectors.
BNE FILLIT ;Jump.
;Update directory.
CUPD: LDAZ SVHSEC ;Read HDS into FBUF1.
STAZ CSEC ;Get hole dir. sector.
STAZ SVOSEC ;Save other sector number for WBUFS.
LDAI 0 ;Track zero.
STAZ CTRK
JSR REED ;Read hole dir. sector.
BEQ FIXDIR
DJMP: JMP DIRERR ;Directory read error.
FIXDIR: CLV ;V ← 0.
LDAZ SVSEC ;Check if FDS = HDS.
CMPZ SVOSEC
BEQ ZEROX
BIT CKDUPE ;V ← 1. M6.
ZEROX: LDXI 0
LDYZ SVHY ;Get hole dir. index.
UPBLK: LDAZX FBLK ;FBUF1 ← FBLK.
STAY FBUF1 ;Other buffer.
BVS NXTXY ;If FDS = HDS...
STAY FBUF ;write into other buffer too.
NXTXY: INY
INX
CPXI 20 ;FBLK length.
BCC UPBLK
;Find next file.
TYA ;Get HDI.
STAZ SVHY ;Next hole directory index.
BNE MARKIT
INCZ SVHSEC ;Next hole directory sector.
INCZ SVHSEC
MARKIT: LDYZ FDI ;Update old file record.
LDAI 0 ;0 = Not FMARK or HMARK.
STAY FBUF ;Old file ← empty record.
BVS DIFFS ;Check if HDS = FDS.
STAY FBUF1 ;Mark other buffer too.
JSR WS2TRK ;Write sector on two tracks.
JMP CKDUPE
DIFFS: JSR WBUFS ;Write 4 bufs on 2 tracks.
CKDUPE: BNE DJMP
JSR SETDPO ;Point disk to FBUF.
STAZ CTRK ;CTRK ← 0.
LDAZ SVSEC ;FDS
STAZ CSEC
LDYZ FDI ;Get file dir index.
JMP FNXTF ;Find next file.
DONE: LDAZ HTRK ;FFDT ← next hole track.
STAZ FFTRK ;Update first free data track.
LDAZ HSEC ;FFDS ← nezt hole sector.
STAZ FFSEC ;Update first free data sector.
LDYZ SVHY ;Get first free dir. block.
STYZ FFDIR
LDXZ SVHSEC
DEX ;Unbump.
STXZ DSEC ;Update directory sector count.
LDXI 7
BLTIT: LDAZX DBLK ;BLT Header into directory.
STAX FBUF
DEX
BPL BLTIT
INX ;X ← 0.
STXZ CTRK ;Point to directory track.
INX ;X ← 1.
STXZ CSEC ;Header sector.
JSR WS2TRK ;Write two sectors on two tracks.
BNE UPERR ;Write error.
JMP ACKCLR ;Packed.
UPERR: JMP DIRERR ;?
FORM: JSR GEOT
JSR MOTON ;Turn on motor.
JSR SETDPO ;Point to FBUF.
LDXI 6
CSLOP: LDAX FORMT ;Setup command list.
STAZX CBLK
DEX
BPL CSLOP
TKOOP: LDXI 1 ;First sector.
LDYI 0
SCOOP: LDAZ FOTRK ;Get track number.
STAY FBUF ;And setup I.D.s.
INY
LDAI 0
STAY FBUF ;Head number.
INY
TXA
STAY FBUF ;Sector number.
INY
LDAI 0
STAY FBUF ;Length.
INY
INX ;Next sector.
CPXI =17 ;Sectors per track +1.
BCC SCOOP
JSR WUF ;Write buffer.
JSR BW ;Wait until not busy.
;Add verify 16 sectors? Check disk error?
INCZ FOTRK ;Next track.
LDAZ FOTRK
CMPI =35
BCC TKOOP
LDAZ SVERR ;Check for errors?
BNE UPERR ;Error.
JMP FORMIN ;Init directory.
;Wait for input.
GCHR: LDA SIOC ;Read SI/O status.
LSRA ;Get rcvr. full bit.
BCC GCHR
ANDI 30 ;FE, OVR.
BNE CERR
LDA SIOD ;Input byte.
RTS
CERR: STAZ CEFLG ;Save comm. error.
LDA SIOD ;Read data reg. to reset error.
LDAI 0 ;Return with null?
RTS
GEOT: JSR GCHR ;Wait for EOT.
CMPI 4 ;<EOT>
BNE TERR
LDAZ CEFLG ;Check for comm. error.
BNE TERR ;Jump to comerr?
RTS
TERR: JMP ILCJMP ;Pop up one level to ILLCMD.
;Decimal output routine.
ODEC: CLC
RORA ;/2
STAZ OCTH
TXA
RORA
STAZ OCTL
LDAI =100
JSR GDIG ;Output hundreds.
LDAI =10
JSR GDIG ;Output tens.
LDAZ OCTL
ORAI 60 ;Convert to ascii.
OCHECK: TAX
OCHRCK: TXA
CLC
ADCZ CKSUM ;Update check sum.
STAZ CKSUM
;Output byte in X.
OCHR: LDA SIOC ;Read SI/O status.
ANDI 2 ;Transmiter full bit.
BEQ OCHR
STX SIOD ;Output it.
RTS
PACK: LDXI 20 ;Output <ack>.
BNE OCHR
ACKSTX: JSR PACK ;Output <ack> and <stx>.
PSTX: LDXI 2 ;Output <stx>.
BNE OCHR
RDRVST: LDAI RDSTAT ;Read drive status command.
JSR PCMD
SW: LDA FDSKC ;Read drive status.
BMI SW ;Wait until not busy.
LDA FDSKP ;Get result.
ANDI 20 ;Index bit.
RTS
MOTOFF: LDAI MOFF ;Turn motor off.
JSR PCMD
STYZ MO ;MO ← 0.
RTS
ONES ← =13 ;=10 = 1s?
MOTON: LDXZ MO ;Check if already on.
BNE SPUN
STXZ TL ;Setup timer. X = 0, MO = 0.
LDAI MON ;Turn it on.
JSR PCMD
POW: LDAI ONES
STAZ TH
JSR RDRVST ;Get index bit.
STAZ INDEX
MW: JSR RDRVST ;Check for index.
EORZ INDEX
BEQ CNTDWN ;Check if same as last index.
INX ;Count the index.
EORZ INDEX ;Get new index.
STAZ INDEX
CNTDWN: DECZ TL ;Motor on delay.
BNE MW
DECZ TH
BNE MW
LDAI 377
CPXI 3 ;Check if disk is spining.
BCS SPIN
TAX
TXS ;SP ← 377. Fix stack.
JSR MOTOFF
LDXI 12 ;Drive not ready error.
JMP OCLR
SPIN: STAZ MO ;Set motor on flag.
SPUN: LDAI TWOS
STAZ TH
RTS
GDIG: STAZ DIGIT
LDXI 57 ;"0" -1.
DIGLOP: INX
SEC
LDAZ OCTL
SBCZ DIGIT
STAZ OCTL
BCS DIGLOP
DECZ OCTH
BPL DIGLOP
LDAZ OCTL
ADCZ DIGIT ;C = 0.
STAZ OCTL
INCZ OCTH
JMP OCHRCK ;Output digit and update check sum.
;Reset and interrupt vectors.
LOC ZERO + 177772
NMIV∧377 ;NMI Vector.
NMIV⊗-10
RST∧377 ;Reset vector.
RST⊗-10
IRQV∧377 ;IRQ Vector.
IRQV⊗-10
END